package wiki.xsx.core.jmeter.core;

import lombok.SneakyThrows;
import org.apache.jmeter.JMeter;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.*;

/**
 * jmeter引擎启动器
 *
 * @author xsx
 * @date 2022/8/22
 * @since 1.8
 * <p>
 * Copyright (c) 2022 xsx All Rights Reserved.
 * easy-jmeter is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * </p>
 */
public class JmeterEngineStarter {

    /**
     * 测试计划导出锁
     */
    private static final Object LOCK = new Object();

    static {
        // 设置非gui模式
        System.setProperty(JMeter.JMETER_NON_GUI, "true");
    }

    /**
     * 运行
     *
     * @param testPlan 测试计划
     */
    public static void run(JmeterTestPlan testPlan) {
        // 加载jmeter配置
        JMeterUtils.loadJMeterProperties(testPlan.getPropertiesPath());
        // 运行
        run(testPlan.getPropertiesPath(), testPlan.create());
    }

    /**
     * 运行
     *
     * @param propertiesPath   jmeter配置文件路径
     * @param testPlanHashTree 测试计划配置树
     */
    public static void run(String propertiesPath, HashTree testPlanHashTree) {
        // 初始化保存配置
        initSaveProperty(propertiesPath);
        // 创建引擎
        StandardJMeterEngine engine = new StandardJMeterEngine();
        // 设置测试计划
        engine.configure(testPlanHashTree);
        // 运行
        engine.run();
    }

    /**
     * 加载测试计划
     *
     * @param file jmeter脚本文件
     * @return 返回测试计划配置树
     */
    @SneakyThrows
    public static HashTree load(File file) {
        return SaveService.loadTree(file);
    }

    /**
     * 导出测试计划
     *
     * @param testPlan    测试计划
     * @param outputPath 输出路径
     */
    @SneakyThrows
    public static void export(JmeterTestPlan testPlan, String outputPath) {
        // 获取输出路径
        Path path = Paths.get(outputPath);
        // 创建目录
        Files.createDirectories(path.getParent());
        // 创建输出流
        try (OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE)) {
            // 导出测试计划
            export(testPlan, outputStream);
        }
    }

    /**
     * 导出测试计划
     *
     * @param testPlan      测试计划
     * @param outputStream 输出流
     */
    @SneakyThrows
    public static void export(JmeterTestPlan testPlan, OutputStream outputStream) {
        // 初始化保存配置
        initSaveProperty(testPlan.getPropertiesPath());
        // 保存测试计划配置树
        SaveService.saveTree(testPlan.create(), outputStream);
    }

    /**
     * 初始化保存配置
     *
     * @param propertiesPath jmeter配置文件路径
     */
    @SneakyThrows
    private static void initSaveProperty(String propertiesPath) {
        // 定义属性key
        final String key = "saveservice.properties";
        // 定义默认配置文件路径
        final String defaultPropertyPath = "/org/apache/jmeter/saveservice.properties";
        // 如果jmeter配置未初始化，则加载jmeter配置
        if (JMeterUtils.getJMeterProperties() == null) {
            // 加载jmeter配置
            JMeterUtils.loadJMeterProperties(propertiesPath);
        }
        // 如果未定义保存属性路径，则加载默认路径
        if (JMeterUtils.getProperty(key) == null) {
            // 加锁
            synchronized (LOCK) {
                // 如果仍然未定义，则加载默认路径（双重判断）
                if (JMeterUtils.getProperty(key) == null) {
                    // 定义临时文件
                    File temp = new File(key);
                    // 如果文件不存在，则创建
                    if (!temp.exists()) {
                        // 读取默认配置文件
                        try (InputStream inputStream = JmeterEngineStarter.class.getResourceAsStream(defaultPropertyPath)) {
                            // 如果读取成功，则创建临时文件
                            if (inputStream != null) {
                                // 创建临时文件
                                Files.copy(inputStream, temp.toPath(), StandardCopyOption.REPLACE_EXISTING);
                            }
                        }
                    }
                    // 设置保存属性路径
                    JMeterUtils.setProperty(key, temp.getAbsolutePath());
                }
            }
        }
    }
}